package com.colt.contentcenter.service.share;

import com.alibaba.fastjson.JSON;
import com.colt.contentcenter.dao.ShareInfoMapper;
import com.colt.contentcenter.dao.content.ShareMapper;
import com.colt.contentcenter.dao.midusershare.MidUserShareMapper;
import com.colt.contentcenter.dao.rocketmqtransactionlog.RocketmqTransactionLogMapper;
import com.colt.contentcenter.domain.dto.content.ShareAuditDTO;
import com.colt.contentcenter.domain.dto.content.ShareDTO;
import com.colt.contentcenter.domain.dto.messaging.UserUpdateBonusMsgDTO;
import com.colt.contentcenter.domain.dto.user.UserDTO;
import com.colt.contentcenter.domain.entity.content.Share;
import com.colt.contentcenter.domain.entity.midusershare.MidUserShare;
import com.colt.contentcenter.domain.entity.rocketmqtransactionlog.RocketmqTransactionLog;
import com.colt.contentcenter.domain.enums.AuditStatusEnum;
import com.colt.contentcenter.feighclient.UserCenteFeighrClient;
import com.colt.contentcenter.mq.rocketmq.source.CostBonusSource;
import com.colt.contentcenter.util.FastJsonUtils;
import com.colt.contentcenter.util.RedisServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

/**
 * @program: content-center
 * @description: shareService
 * @author: colt
 * @create: 2020-05-02 10:43
 **/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ShareService {
    private final MidUserShareMapper midUserShareMapper;
    private final ShareMapper shareMapper;
    private final UserCenteFeighrClient userCenteFeighrClient;
    private final RocketMQTemplate rocketMQTemplate;
    private final RocketmqTransactionLogMapper rocketmqTransactionLogMapper;
    private final Source source;
    private final CostBonusSource costBonusSource;
    private final RestTemplate restTemplate;
    private final DiscoveryClient discoveryClient;
    private final ShareInfoMapper shareInfoMapper;
    private final RedisServiceImpl redisService;
    public List<Share> getShareAllInfo(){
        List<Share> shareList = null;
        String shares = redisService.get("allShares");
        if (shares != null||!shares.equals("")){
            shareList = FastJsonUtils.getJsonToList(shares, Share.class);
            return shareList;
        }
        shareList = this.shareInfoMapper.selectShareInfo();
        redisService.set("allShares",FastJsonUtils.toJsonStr(shareList));
        return shareList;
    }
    public ShareDTO findById(Integer id){
        Share share = this.shareMapper.selectByPrimaryKey(id);
        UserDTO dto = this.userCenteFeighrClient.findById(id);
        ShareDTO shareDTO = new ShareDTO();
        BeanUtils.copyProperties(share,shareDTO);
        shareDTO.setWxId(dto.getWxId());
        shareDTO.setWxNickname(dto.getWxNickname());
        return shareDTO;
    }
    public ShareDTO findByIdTest(Integer id){
        Share share = this.shareMapper.selectByPrimaryKey(id);
        ResponseEntity<UserDTO> userDTOResponseEntity = restTemplate.getForEntity("http://localhost:8080/users/{id}", UserDTO.class, share.getUserId());
        //消息装配
        /**/

        List<ServiceInstance> instances = discoveryClient.getInstances("user-center");
        instances.forEach(i-> System.out.println(i.toString()));
        List<String> targetUrls =
                instances.stream().map(instance -> instance.getUri().toString() + "/users/{id}")
                        .collect(Collectors.toList());
        //在url集合里随机获取一个
        int targetUrlIndex = ThreadLocalRandom.current().nextInt(targetUrls.size());
        String targetUrl = targetUrls.get(targetUrlIndex);
        log.info("获取到的url:{}",targetUrl);
//        ResponseEntity<UserDTO> entity = restTemplate.getForEntity(targetUrl, UserDTO.class, share.getUserId());
        ResponseEntity<UserDTO> entity = restTemplate.getForEntity("http://user-center/users/{userId}", UserDTO.class, share.getUserId());
        HttpStatus statusCode = entity.getStatusCode();
        return null;
    }

    private HttpServletRequest getHttpServletRequest() {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) attributes;
        return servletRequestAttributes.getRequest();
    }



    public Share findByExample(Share share){
        return this.shareMapper.selectOneByExample(share);
    }

//    这里不再需要@Tranactional注解，我们主要靠mq分布式事务去实现
    public Share auditById(Integer id, ShareAuditDTO shareAuditDTO) {
        /**
        * @Description: 管理员审核分享
        * @Param: [id, shareAuditDTO]
        * @return: com.colt.contentcenter.domain.entity.content.Share
        * @Author: colt
        * @Date: 2020/11/6
        */
        //查询share是否存在，不存在或者当前的audit_status != NOT_YET，那么抛出异常
        Share share = this.shareMapper.selectByPrimaryKey(id);
        if (null==share){
            throw new IllegalArgumentException("参数非法！该分享不存在！");
        }
        if (Objects.equals("PASS",share.getAuditStatus())){
            throw new IllegalArgumentException("参数非法！该分享已经被审核！");
        }
        //如果为PASS,发消息给rocketMQ，让用户中心去消费,并为发布人添加积分
        if (AuditStatusEnum.PASS.equals(shareAuditDTO.getAuditStatusEnum())){
            UUID transactionId = UUID.randomUUID();
            //发送半消息
            this.source.output()
                    .send(MessageBuilder
                            .withPayload(
                                    UserUpdateBonusMsgDTO.builder()
                                            .userId(share.getUserId())
                                            .bonus(50)
                                            .description("投稿获取积分！")
                                            .event("CONTRIBUTE")
                                            .build()
                            )//此header也有妙用.传参数
                            .setHeader(RocketMQHeaders.TRANSACTION_ID, transactionId)
                            .setHeader("shareId",id)
                            .setHeader("dto",JSON.toJSONString(shareAuditDTO))
                            .setHeader("share",JSON.toJSONString(shareAuditDTO))
                            .build());
//            sendMsgByMq(share,transactionId,id,shareAuditDTO);
        } else {
            //调用审核分享逻辑
            this.auditByIdInDB(id,shareAuditDTO);
        }

        return share;
    }
    @Transactional(rollbackFor = Exception.class)
    public void recordBonusBuyShare(Integer userId, Integer shareId){
        this.midUserShareMapper.insertSelective(
                MidUserShare.builder()
                        .shareId(shareId)
                        .userId(userId)
                        .build()
        );
    }
    @Transactional(rollbackFor = Exception.class)
    public void auditByIdInDB(Integer shareId,ShareAuditDTO shareAuditDTO) {
        /**
        * @Description: 审核分享
        * @Param: [shareId, shareAuditDTO]
        * @return: void
        * @Author: colt
        * @Date: 2020/11/9
        */
        this.shareMapper.updateByPrimaryKeySelective(Share.builder()
                .id(shareId)
                .auditStatus(shareAuditDTO.getAuditStatusEnum().toString())
                .reason(shareAuditDTO.getReason())
                .build());
        //把share写到缓存
    }

    public void sendMsgByMq(Share share,UUID transactionId,Integer id,ShareAuditDTO shareAuditDTO){
           this.rocketMQTemplate.sendMessageInTransaction(
                "tx-add-bonus-group",
                    "add-bonus-share",
//                    此地方必须为消息类型
                    MessageBuilder
                            .withPayload(
                            UserUpdateBonusMsgDTO.builder()
                                    .userId(share.getUserId())
                                    .bonus(50)
                                    .event("CONTRIBUTE")
                                    .description("分享审核通过添加积分！")
                                    .build()
                    )//此header也有妙用
                     .setHeader(RocketMQHeaders.TRANSACTION_ID, transactionId)
                     .setHeader("shareId",id).build()
                    //此参数有大用处
                    ,shareAuditDTO
            );
    }
    @Transactional(rollbackFor = Exception.class)
    public void bonusBuyShareRocketMqLog(String transactionId, Integer userId, Integer shareId){
        /**
        * @Description:  积分购买分享日志记录表，本地事务执行成功将日志插入此表，后续检查事务使用
        * @Param: []
        * @return: void
        * @Author: colt
        * @Date: 2020/11/9
        */

        /*
        *插入用户购买分享记录
        * */
        recordBonusBuyShare(userId,shareId);
//        rocketmq日志记录
        this.rocketmqTransactionLogMapper.insertSelective(
                RocketmqTransactionLog.builder()
                .transactionId(transactionId)
                .log("积分购买分享..")
                .build()
        );
    }

    @Transactional(rollbackFor = Exception.class)
    public void auditByIdWithRocketMqLog(Integer id,ShareAuditDTO auditDTO,String transactionId){
        /** 
        * @Description: 审核分享日志记录表，本地事务执行成功将日志插入此表，后续检查事务使用
        * @Param: [id, auditDTO, transactionId] 
        * @return: void 
        * @Author: colt 
        * @Date: 2020/11/7 
        */ 
        this.auditByIdInDB(id,auditDTO);
        this.rocketmqTransactionLogMapper.insertSelective(
                RocketmqTransactionLog.builder()
                .transactionId(transactionId)
                .log("审核分享..")
                .build()
        );
    }
    public ShareDTO query(UserDTO userDTO) {
        UserDTO dto = userCenteFeighrClient.query(userDTO);
        return new ShareDTO();
    }

    public PageInfo<Share> queryPage(String title, Integer userId, Integer pageNo, Integer pageSize) {

        PageHelper.startPage(pageNo, pageSize);
        //利用了mybatis的拦截器，会切入这条没有分页的sql,自动拼接分页的sql
        List<Share> shares = this.shareMapper.selectByParam(title);
        List<Share> shareDealed = new ArrayList<>();
//              如果用户未登录，downloadURl全部设为null
        if (userId == null){
            shareDealed = shares.stream().peek(
                    share -> {
                        share.setDownloadUrl(null);
                    }
            ).collect(Collectors.toList());
        }else {
            shareDealed = shares.stream().peek(
                    share -> {
                        MidUserShare midUserShare = this.midUserShareMapper.selectOne(
                                MidUserShare.builder()
                                        .userId(userId)
                                        .shareId(share.getId())
                                        .build()
                        );
                        if (midUserShare == null){
                            share.setDownloadUrl(null);
                        }
                    }
            ).collect(Collectors.toList());
        }
//        如果用户登录了，查询mid_user_share 若没有数据，那么这条downloadUrl也设置为null


        return new PageInfo<Share>(shareDealed);
    }


    public Share exchangeByIdMQ(Integer shareId) {
        //根据id查询share是否存在
        Share share = this.shareMapper.selectByPrimaryKey(shareId);
        if (share == null) {
            throw new IllegalArgumentException("该分享不存在！");
        }
        //根据当前登录用户的id查询积分是否够
        HttpServletRequest request = getHttpServletRequest();
        Integer buyerId = (Integer) request.getAttribute("id");
        System.err.println(buyerId);
       /* MidUserShare select = this.midUserShareMapper.selectOne(
                MidUserShare.builder()
                        .userId(buyerId)
                        .shareId(share.getId())
                        .build()
        );
//        若当已经存在 则直接返回
        if (select!=null){
            return share;
        }*/

        UserDTO userDTO = userCenteFeighrClient.findById(buyerId);
//        获取用户积分
        Integer userBonus = userDTO.getBonus();
//        获取分享积分价格
        Integer price = share.getPrice();
        if (userBonus < price) {
            throw new IllegalArgumentException("用户积分余额不足！");
        }
        log.info("userBonus = {},price = {}",userBonus,price);
        //扣减积分&在mid_user_share插入记录
        UUID transactionId = UUID.randomUUID();
        this.costBonusSource.outPut()
                .send(MessageBuilder
                        .withPayload(
                                UserUpdateBonusMsgDTO.builder()
                                        .loginId(buyerId)
                                        .userId(share.getUserId())
                                        .description("用户积分购买分享..")
                                        .event("BUY")
                                        .bonus(price)
                                        .build()
                        )//此header也有妙用.传参数
                        .setHeader(RocketMQHeaders.TRANSACTION_ID,transactionId)
                        .setHeader("shareId", shareId)
                        .setHeader("ownerId",share.getUserId())
                        .setHeader("userId",buyerId)
                        .build());
        return share;
    }
    public Share exchangeByIdFeigh(Integer id) {
        //根据id查询share是否存在
        Share share = this.shareMapper.selectByPrimaryKey(id);
        if (share == null||!share.getAuditStatus().equals(AuditStatusEnum.PASS)) {
            throw new IllegalArgumentException("该分享不存在！");
        }
        //根据当前登录用户的id查询积分是否够
        HttpServletRequest request = getHttpServletRequest();
        Integer userPrKey = (Integer) request.getAttribute("id");
        MidUserShare select = this.midUserShareMapper.selectOne(
                MidUserShare.builder()
                        .userId(userPrKey)
                        .shareId(share.getId())
                        .build()
        );
//        若当已经存在 则直接返回
        if (select!=null){
            return share;
        }
        UserDTO userDTO = userCenteFeighrClient.findById(userPrKey);
//        获取用户积分
        Integer userBonus = userDTO.getBonus();
//        获取分享积分价格
        Integer price = share.getPrice();
        if (userBonus < price) {
            throw new IllegalArgumentException("用户积分余额不足！");
        }
        //扣减积分&在mid_user_share插入记录
        UserDTO dto = this.userCenteFeighrClient.addBonus(
                UserUpdateBonusMsgDTO.builder()
                        .bonus(0-price)
                        .userId(userDTO.getId())
                        .build()
        );
        this.midUserShareMapper.insert(MidUserShare.builder()
                .shareId(share.getId())
                .userId(userDTO.getId())
                .build());
        return share;
    }
}
